package com.ideaaedi.commonspring.threadpool;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.task.TaskDecorator;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;

/**
 * 线程池配置
 * <br/><br/>
 * 示例：
 * <pre>
 *   import com.ideaaedi.commonspring.decorator.MDCTaskDecorator;
 *   import com.ideaaedi.commonspring.threadpool.ThreadPoolBuilder;
 *   import org.springframework.context.annotation.Bean;
 *   import org.springframework.context.annotation.Configuration;
 *   import org.springframework.scheduling.annotation.EnableAsync;
 *   import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 *
 *   import java.util.concurrent.ThreadPoolExecutor;
 *
 *
 *  \@EnableAsync
 *  \@Configuration
 *  public class ThreadPoolConfig {
 *
 *      public static final String MINE_EXECUTOR_NAME = "mineExecutor";
 *
 *      \@Bean(MINE_EXECUTOR_NAME)
 *      public ThreadPoolTaskExecutor mineExecutor() {
 *          int processors = Runtime.getRuntime().availableProcessors();
 *          return ThreadPoolBuilder.builder()
 *                  .corePoolSize(2 * processors + 1)
 *                  .maxPoolSize(100)
 *                  .queueCapacity(500)
 *                  .keepAliveSeconds(60)
 *                  .threadNamePrefix("rpc-log-recorder-")
 *                  .rejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy())
 *                  .taskDecorator(new MDCTaskDecorator())
 *                  .buildAndInitialize();
 *      }
 *  }
 * </pre>
 *
 * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
 * @since 1.0.0
 */
public class ThreadPoolBuilder {
    
    /** 核心线程数 */
    @Getter
    @Setter(AccessLevel.PRIVATE)
    private Integer corePoolSize;
    
    /** 最大线程数 */
    @Getter
    @Setter(AccessLevel.PRIVATE)
    private Integer maxPoolSize;
    
    /** 活跃时长 */
    @Getter
    @Setter(AccessLevel.PRIVATE)
    private Integer keepAliveSeconds;
    
    /** 队列容量 */
    @Getter
    @Setter(AccessLevel.PRIVATE)
    private Integer queueCapacity;
    
    /** 线程名前缀 */
    @Getter
    @Setter(AccessLevel.PRIVATE)
    private String threadNamePrefix;
    
    /** 线程装饰器 */
    @Getter
    @Setter(AccessLevel.PRIVATE)
    private TaskDecorator taskDecorator;
    
    /** 拒绝策略 */
    @Getter
    @Setter(AccessLevel.PRIVATE)
    private RejectedExecutionHandler rejectedExecutionHandler;
    
    
    @Getter
    @Setter(AccessLevel.PRIVATE)
    private Boolean allowCoreThreadTimeOut;
    
    @Getter
    @Setter(AccessLevel.PRIVATE)
    private Integer awaitTerminationSeconds;
    
    @Getter
    @Setter(AccessLevel.PRIVATE)
    private Boolean daemon;
    
    @Getter
    @Setter(AccessLevel.PRIVATE)
    private String beanName;
    
    @Getter
    @Setter(AccessLevel.PRIVATE)
    private ThreadFactory threadFactory;
    
    @Getter
    @Setter(AccessLevel.PRIVATE)
    private ThreadGroup threadGroup;
    
    @Getter
    @Setter(AccessLevel.PRIVATE)
    private Integer threadPriority;
    
    @Getter
    @Setter(AccessLevel.PRIVATE)
    private Boolean waitForJobsToCompleteOnShutdown;
    
    public ThreadPoolBuilder allowCoreThreadTimeOut(boolean allowCoreThreadTimeOut) {
        this.setAllowCoreThreadTimeOut(allowCoreThreadTimeOut);
        return this;
    }
    
    public ThreadPoolBuilder daemon(boolean daemon) {
        this.setDaemon(daemon);
        return this;
    }
    
    public ThreadPoolBuilder awaitTerminationSeconds(int awaitTerminationSeconds) {
        this.setAwaitTerminationSeconds(awaitTerminationSeconds);
        return this;
    }
    
    public ThreadPoolBuilder beanName(String beanName) {
        this.setBeanName(beanName);
        return this;
    }
    
    public ThreadPoolBuilder threadFactory(ThreadFactory threadFactory) {
        this.setThreadFactory(threadFactory);
        return this;
    }
    
    public ThreadPoolBuilder threadGroup(ThreadGroup threadGroup) {
        this.setThreadGroup(threadGroup);
        return this;
    }
    
    public ThreadPoolBuilder threadPriority(int threadPriority) {
        this.setThreadPriority(threadPriority);
        return this;
    }
    
    public ThreadPoolBuilder waitForJobsToCompleteOnShutdown(boolean waitForJobsToCompleteOnShutdown) {
        this.setWaitForJobsToCompleteOnShutdown(waitForJobsToCompleteOnShutdown);
        return this;
    }
    
    public static ThreadPoolBuilder builder() {
        return new ThreadPoolBuilder();
    }
    
    public ThreadPoolBuilder corePoolSize(int corePoolSize) {
        this.setCorePoolSize(corePoolSize);
        return this;
    }
    
    public ThreadPoolBuilder maxPoolSize(int maxPoolSize) {
        this.setMaxPoolSize(maxPoolSize);
        return this;
    }
    
    public ThreadPoolBuilder keepAliveSeconds(int keepAliveSeconds) {
        this.setKeepAliveSeconds(keepAliveSeconds);
        return this;
    }
    
    public ThreadPoolBuilder queueCapacity(int queueCapacity) {
        this.setQueueCapacity(queueCapacity);
        return this;
    }
    
    public ThreadPoolBuilder threadNamePrefix(String threadNamePrefix) {
        this.setThreadNamePrefix(threadNamePrefix);
        return this;
    }
    
    public ThreadPoolBuilder taskDecorator(TaskDecorator taskDecorator) {
        this.setTaskDecorator(taskDecorator);
        return this;
    }
    
    public ThreadPoolBuilder rejectedExecutionHandler(RejectedExecutionHandler rejectedExecutionHandler) {
        this.setRejectedExecutionHandler(rejectedExecutionHandler);
        return this;
    }
    
    /**
     * 构建并初始化
     */
    public ThreadPoolTaskExecutor buildAndInitialize() {
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        Integer corePoolSize = this.getCorePoolSize();
        if (corePoolSize != null) {
            threadPoolTaskExecutor.setCorePoolSize(corePoolSize);
        }
        Integer maxPoolSize = this.getMaxPoolSize();
        if (maxPoolSize != null) {
            threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize);
        }
        Integer keepAliveSeconds = this.getKeepAliveSeconds();
        if (keepAliveSeconds != null) {
            threadPoolTaskExecutor.setKeepAliveSeconds(keepAliveSeconds);
        }
        Integer queueCapacity = this.getQueueCapacity();
        if (queueCapacity != null) {
            threadPoolTaskExecutor.setQueueCapacity(queueCapacity);
        }
        String threadNamePrefix = this.getThreadNamePrefix();
        if (StringUtils.isNotEmpty(threadNamePrefix)) {
            threadPoolTaskExecutor.setThreadNamePrefix(threadNamePrefix);
        }
        TaskDecorator taskDecorator = this.getTaskDecorator();
        if (taskDecorator != null) {
            threadPoolTaskExecutor.setTaskDecorator(taskDecorator);
        }
        RejectedExecutionHandler rejectedExecutionHandler = this.getRejectedExecutionHandler();
        if (rejectedExecutionHandler != null) {
            threadPoolTaskExecutor.setRejectedExecutionHandler(rejectedExecutionHandler);
        }
        Boolean allowCoreThreadTimeOut = this.getAllowCoreThreadTimeOut();
        if (allowCoreThreadTimeOut != null) {
            threadPoolTaskExecutor.setAllowCoreThreadTimeOut(allowCoreThreadTimeOut);
        }
        Integer awaitTerminationSeconds = this.getAwaitTerminationSeconds();
        if (awaitTerminationSeconds != null) {
            threadPoolTaskExecutor.setAwaitTerminationSeconds(awaitTerminationSeconds);
            
        }
        Boolean daemon = this.getDaemon();
        if (daemon != null) {
            threadPoolTaskExecutor.setDaemon(daemon);
        }
        String beanName = this.getBeanName();
        if (beanName != null) {
            threadPoolTaskExecutor.setBeanName(beanName);
        }
        ThreadFactory threadFactory = this.getThreadFactory();
        if (threadFactory != null) {
            threadPoolTaskExecutor.setThreadFactory(threadFactory);
        }
        ThreadGroup threadGroup = this.getThreadGroup();
        if (threadGroup != null) {
            threadPoolTaskExecutor.setThreadGroup(threadGroup);
        }
        Integer threadPriority = this.getThreadPriority();
        if (threadPriority != null) {
            threadPoolTaskExecutor.setThreadPriority(threadPriority);
        }
        Boolean waitForJobsToCompleteOnShutdown = this.getWaitForJobsToCompleteOnShutdown();
        if (waitForJobsToCompleteOnShutdown != null) {
            threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(waitForJobsToCompleteOnShutdown);
        }
        threadPoolTaskExecutor.initialize();
        return threadPoolTaskExecutor;
    }
    
    
}